/* Copyright (c) 2024 Qualcomm Technologies International, Ltd. */
/* %%version */


#include "csr_synergy.h"
#ifndef EXCLUDE_GATT_OTS_CLIENT_MODULE
#include "mcp.h"
#include "mcp_debug.h"
#include "mcp_common.h"
#include "mcp_ots_operation_handler.h"

/*---------------------------Static Function Definitions------------------------------*/
static bool validateHandles(MCP *mcpInst, ServiceHandle mcsHandle)
{
    /* Check if the client handle is a valid one and its for GMCS(currently OTS is supported for GMCS only)*/
    if (mcpIsValidMcsInst(mcpInst, mcsHandle) && mcpInst->mcsSrvcHndl == mcsHandle)
    {
         return TRUE;
    }
    return FALSE;
}

void mcpSendOtsRegisterForIndCfm(MCP *mcpInst,
                                ServiceHandle otsServiceHandle,
                                McpStatus status,
                                uint16 resultSupplier)
{
    McpOtsIndCfm *message = CsrPmemZalloc(sizeof(*message));

    message->id = MCP_OTS_IND_CFM;
    message->prflHndl = mcpInst->mcpSrvcHndl;
    message->srvcHndl = otsServiceHandle;
    message->resultSupplier = resultSupplier;
    message->status = status;

    McpMessageSend(mcpInst->appTask, message);
}

void mcpSendObjContentCfm(MCP *mcpInst, const GattOtscReadObjectCfm *msg, uint16 status, uint16 resultSupplier)
{
    McpGetObjectContentsByObjIdCfm* message = CsrPmemZalloc(sizeof(*message));

    message->id = MCP_GET_OBJECT_CONTENTS_BY_OBJ_ID_CFM;
    message->prflHndl = mcpInst->mcpSrvcHndl;
    message->srvcHndl = mcpInst->mcsSrvcHndl;

    message->status = status;

    if (msg)
    {
        message->status     = msg->resultCode;
        message->moreToCome = msg->moreToCome;

        if (msg->dataLen)
        {
            message->data    = msg->data;
            message->dataLen = msg->dataLen;
        }
    }
    message->resultSupplier = resultSupplier;

    if (mcpInst->pendingOp & MCP_PENDING_OP_SELECT_OBJECT)
    {
        mcpInst->pendingOp &= ~MCP_PENDING_OP_SELECT_OBJECT;
    }
    else
    {
        mcpInst->pendingOp &= ~MCP_PENDING_OP_READ_OBJECT;
    }

    McpMessageSend(mcpInst->appTask, message);
}

void mcpSendObjectMetadataInd(MCP *mcpInst, const GattOtscReadObjectMetadataCfm *metaData)
{
    McpGetObjectMetadataCommonInd *message = NULL;

    if (metaData->characId)
    {
        message = CsrPmemZalloc(sizeof(*message));

        message->prflHndl = mcpInst->mcpSrvcHndl;
        message->srvcHndl = mcpInst->mcsSrvcHndl;

        if (metaData->value && metaData->valueLen)
        {
            message->valueLength = metaData->valueLen;
            message->value = metaData->value;
        }
    }

    switch (metaData->characId)
    {
        case GATT_OTSC_CHARAC_ID_OBJ_NAME:
        {
            message = (McpDiscoverObjectSizeInd *)message;
            message->id = MCP_DISCOVER_OBJECT_NAME_IND;
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_TYPE:
        {
            message = (McpDiscoverObjectTypeInd *)message;
            message->id = MCP_DISCOVER_OBJECT_TYPE_IND;
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_SIZE:
        {
            message = (McpDiscoverObjectSizeInd *)message;
            message->id = MCP_DISCOVER_OBJECT_SIZE_IND;
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_ID:
        {
            message = (McpDiscoverObjectIdInd *)message;
            message->id = MCP_DISCOVER_OBJECT_ID_IND;
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_PROPERTIES:
        {
            message = (McpDiscoverObjectPropInd *)message;
            message->id = MCP_DISCOVER_OBJECT_PROP_IND;
            break;
        }
        default:
            MCP_DEBUG("mcpSendObjectMetadataInd unknown metaData->characId :%x\n", metaData->characId);
    }
    if (metaData->characId)
    {
        McpMessageSend(mcpInst->appTask, message);
        mcpInst->mcpReqCount--;
    }
    else
    {
        MCP_DEBUG("Error in Metadata char reading from remote\n");
    }
}

void mcpSendObjectMetadataCfm(MCP *mcpInst, const GattOtscReadObjectMetadataCfm *metaData)
{
    McpGetObjectMetadataCommonCfm *message = NULL;

    if (metaData->characId)
    {
        message = CsrPmemZalloc(sizeof(*message));

        message->prflHndl = mcpInst->mcpSrvcHndl;
        message->srvcHndl = mcpInst->mcsSrvcHndl;
        message->resultSupplier = CSR_BT_MCP_GET_SUPPLIER(metaData->resultCode);
        message->status = metaData->resultCode;

        if (metaData->value && metaData->valueLen)
        {
            message->valueLength = metaData->valueLen;
            message->value = metaData->value;
        }
    }

    switch(metaData->characId)
    {
         case GATT_OTSC_CHARAC_ID_OBJ_NAME:
         {
              message = (McpGetCurrentMediaObjectNameCfm*)message;
              message->id = MCP_GET_CURRENT_MEDIA_OBJECT_NAME_CFM;

              mcpInst->otsMetadataType =  mcpInst->otsMetadataType & ~GATT_OTSC_CHARAC_ID_OBJ_NAME;
              break;
         }
         case GATT_OTSC_CHARAC_ID_OBJ_TYPE:
         {
              message = (McpGetCurrentMediaObjectSizeCfm*)message;
              message->id = MCP_GET_CURRENT_MEDIA_OBJECT_TYPE_CFM;

              mcpInst->otsMetadataType =  mcpInst->otsMetadataType & ~GATT_OTSC_CHARAC_ID_OBJ_TYPE;
              break;
         }
         case GATT_OTSC_CHARAC_ID_OBJ_SIZE:
         {
              message = (McpGetCurrentMediaObjectSizeCfm*)message;
              message->id = MCP_GET_CURRENT_MEDIA_OBJECT_SIZE_CFM;

              mcpInst->otsMetadataType =  mcpInst->otsMetadataType & ~GATT_OTSC_CHARAC_ID_OBJ_SIZE;
              break;
         }
         case GATT_OTSC_CHARAC_ID_OBJ_ID:
         {
              message = (McpGetCurrentMediaObjectIdCfm*)message;
              message->id = MCP_GET_CURRENT_MEDIA_OBJECT_ID_CFM;

              mcpInst->otsMetadataType =  mcpInst->otsMetadataType & ~GATT_OTSC_CHARAC_ID_OBJ_ID;
              break;
         }
         case GATT_OTSC_CHARAC_ID_OBJ_PROPERTIES:
         {
              message = (McpGetCurrentMediaObjectPropCfm*)message;
              message->id = MCP_GET_CURRENT_MEDIA_OBJECT_PROP_CFM;

              mcpInst->otsMetadataType =  mcpInst->otsMetadataType & ~GATT_OTSC_CHARAC_ID_OBJ_PROPERTIES;
              break;
         }
         default:
           MCP_DEBUG("mcpSendObjectMetadataCfm unknown metaData->characId :%x\n", metaData->characId);
    }

    if (mcpInst->otsMetadataType == 0x00)
    {
        mcpInst->pendingOp &= ~MCP_PENDING_OP_READ_OBJECT_METADATA;
    }

    if (metaData->characId)
    {
        McpMessageSend(mcpInst->appTask, message);
    }
    else
    {
        MCP_DEBUG("Error in Metadata char reading from remote\n");
    }
}

void mcpSendOtsReqAbortCfm(MCP *mcpInst,
                                 McpStatus status,
                                 uint16 resultSupplier)
{
    McpAbortOtsProcedureCfm* message = CsrPmemAlloc(sizeof(*message));

    message->id = MCP_ABORT_OTS_PROCEDURE_CFM;
    message->prflHndl = mcpInst->mcpSrvcHndl;
    message->srvcHndl = mcpInst->mcsSrvcHndl;
    message->status = status;
    message->resultSupplier = resultSupplier;

    McpMessageSend(mcpInst->appTask, message);
}

void mcpSendOtsObjChangedInd(MCP *mcpInst,
                                 GattOtscObjectChangedInd *msg)
{
    McpObjectChangedInd* message = CsrPmemAlloc(sizeof(*message));

    message->id = MCP_OBJECT_CHANGED_IND;
    message->srvcHndl = mcpInst->mcsSrvcHndl;

    memcpy(&message->objectId, &msg->objectId, GATT_OTSC_OBJ_SIZE);

    message->modifier = msg->modifier;
    message->changeType = msg->modification;

    McpMessageSend(mcpInst->appTask, message);
}

void mcpSendStartDiscoverObjCfm(MCP *mcpInst,
                                 McpStatus status,
                                 uint16 resultSupplier)
{
    McpStartDiscoverObjectCfm *message = CsrPmemAlloc(sizeof(*message));

    message->id = MCP_START_DISCOVER_OBJECT_CFM;
    message->prflHndl = mcpInst->mcpSrvcHndl;
    message->srvcHndl = mcpInst->mcsSrvcHndl;
    message->status = status;
    message->resultSupplier = resultSupplier;

    mcpInst->pendingOp &= ~MCP_PENDING_OP_START_OBJECT_DISCOVERY;

    McpMessageSend(mcpInst->appTask, message);

}

void mcpSendStopDiscoverObjCfm(MCP *mcpInst, McpStatus status, uint16 resultSupplier)
{
    McpStartDiscoverObjectCfm *message = CsrPmemAlloc(sizeof(*message));

    message->id = MCP_STOP_DISCOVER_OBJECT_CFM;
    message->prflHndl = mcpInst->mcpSrvcHndl;
    message->srvcHndl = mcpInst->mcsSrvcHndl;
    message->status = status;
    message->resultSupplier = resultSupplier;

    mcpInst->pendingOp &= ~MCP_PENDING_OP_STOP_OBJECT_DISCOVERY;

    McpMessageSend(mcpInst->appTask, message);

}

void McpRegisterForObjChangedIndReq(McpProfileHandle profileHandle,
                                 ServiceHandle mcsHandle,
                                 GattOtscCharacValuesMask charValsMask)
{
    /* handler function for processing ots procedure for enabling/disabling indication */
    MCP *mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (validateHandles(mcpInst, mcsHandle))
    {
        GattOtscRegisterForIndicationReq(mcpInst->otsSrvcHndl, charValsMask);
    }
    else
    {
        mcpSendOtsRegisterForIndCfm(mcpInst, mcpInst->otsSrvcHndl, MCP_STATUS_INVALID_PARAMETER, GATT_SUPPLIER_MCP_CLIENT);
    }
}

void McpGetObjectContentsByObjIdReq(McpProfileHandle profileHandle,
                             ServiceHandle mcsHandle,
                             const GattOtscObjectId objId,
                             bool readObject,
                             uint16 readOffset,
                             uint32 objectLength)
{
    MCP *mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (validateHandles(mcpInst, mcsHandle))
    {
        /* OTS API's are sync in nature so first check return type to decide cfm will come or not from OTS */
        if (GattOtscSelectObjectReq(mcpInst->otsSrvcHndl, objId, GATT_OTSC_OBJ_LIST_OP_GOTO))
        {
            if (readObject)
            {
                mcpInst->pendingOp |= MCP_PENDING_OP_READ_OBJECT;
            }
            else
            {
                mcpInst->pendingOp |= MCP_PENDING_OP_SELECT_OBJECT;
            }
        }
        else
        {
             mcpSendObjContentCfm(mcpInst, NULL, MCP_STATUS_OTS_FAILED, GATT_SUPPLIER_MCP_CLIENT);
        }
    }
    else
    {
        mcpSendObjContentCfm(mcpInst, NULL, MCP_STATUS_INVALID_PARAMETER, GATT_SUPPLIER_MCP_CLIENT);
    }

    CSR_UNUSED(readOffset);
    CSR_UNUSED(objectLength);
}

void McpGetCurrentMediaObjMetadataReq(McpProfileHandle profileHandle,
                                        ServiceHandle mcsHandle,
                                        McpObjectMetadataType objectMetadataType)
{
    MCP *mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (validateHandles(mcpInst, mcsHandle))
    {
        if (objectMetadataType)
        {
            mcpInst->pendingOp |= MCP_PENDING_OP_READ_OBJECT_METADATA;
            mcpInst->otsMetadataType = objectMetadataType;
            PerformObjectMetadataRead(mcpInst, objectMetadataType);
        }
        else
        {
            MCP_INFO("Invalid objectMetadataType passed by application objectMetadataType%x\n", objectMetadataType);
        }
    }
    else
    {
       MCP_INFO("Invalid mcsHandle passed by application mcsHandle%x\n", mcsHandle);
    }
}

void McpStartDiscoverAllObjReq(McpProfileHandle profileHandle,
                               ServiceHandle mcsHandle,
                               McpObjectMetadataType objMetadataType,
                               GattOtscObjectFilters         filters,
                               GattOtscFilterByNameInfo      *nameInfo,
                               GattOtscFilterByDateInfo      *dateInfo,
                               GattOtscFilterByObjSizeInfo   *objSizeInfo,
                               CsrBtUuid                     objectUuid)
{
    MCP *mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (validateHandles(mcpInst, mcsHandle) && objMetadataType)
    {
        /* OTS API's are sync in nature so first check return type to decide cfm will come or not from OTS */
        if (GattOtscFilterObjectsReq(mcpInst->otsSrvcHndl, GATT_OTSC_FILTER_NONE,
            NULL, NULL, NULL, OTSC_INVALID_OBJECT_UUID))
        {
            mcpInst->otsMetadataType = objMetadataType;
        }
        else
        {
            mcpSendStartDiscoverObjCfm(mcpInst, MCP_STATUS_OTS_FAILED, GATT_SUPPLIER_MCP_CLIENT);
        }
    }
    else
    {
        mcpSendStartDiscoverObjCfm(mcpInst, MCP_STATUS_INVALID_PARAMETER, GATT_SUPPLIER_MCP_CLIENT);
    }

    CSR_UNUSED(filters);
    CSR_UNUSED(nameInfo);
    CSR_UNUSED(dateInfo);
    CSR_UNUSED(objSizeInfo);
    CSR_UNUSED(objectUuid);
}

void McpStopDiscoverObjectsReq(McpProfileHandle profileHandle,
                               ServiceHandle mcsHandle)
{
    MCP *mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (validateHandles(mcpInst, mcsHandle))
    {
         /* If nothing is on going then simply send confirmation or discovery is not started */
         if (!(mcpInst->pendingOp & MCP_PENDING_OP_START_OBJECT_DISCOVERY) ||
             mcpInst->pendingOp == MCP_PENDING_OP_NONE)
         {
            mcpSendStopDiscoverObjCfm(mcpInst, MCP_STATUS_SUCCESS, GATT_SUPPLIER_MCP_CLIENT);
            return;
         }
          mcpInst->pendingOp |= MCP_PENDING_OP_STOP_OBJECT_DISCOVERY;
    }
    else
    {
         mcpSendStopDiscoverObjCfm(mcpInst, MCP_STATUS_INVALID_PARAMETER, GATT_SUPPLIER_MCP_CLIENT);
    }
}

void McpAbortOtsProcedureReq(McpProfileHandle profileHandle,
                             ServiceHandle mcsHandle)
{
    MCP *mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (validateHandles(mcpInst, mcsHandle))
    {
        /* OTS API's are sync in nature so first check return type to decide cfm will come or not from OTS */
        if (!GattOtscAbortReq(mcpInst->otsSrvcHndl))
        {
            mcpSendOtsReqAbortCfm(mcpInst, MCP_STATUS_OTS_FAILED, GATT_SUPPLIER_MCP_CLIENT);
        }
    }
    else
    {
        mcpSendOtsReqAbortCfm(mcpInst, MCP_STATUS_INVALID_PARAMETER, GATT_SUPPLIER_MCP_CLIENT);
    }
}

GattOtscDeviceData* McpGetOtsAttributeHandles(McpProfileHandle profileHandle, ServiceHandle mcsHandle)
{
    MCP* mcpInst = ServiceHandleGetInstanceData((ServiceHandle)profileHandle);

    if (mcpInst)
    {
        /* Check if the client handle is a valid one */
        if (validateHandles(mcpInst, mcsHandle))
        {
            return GattOtscGetHandlesReq(mcpInst->otsSrvcHndl);
        }
        return NULL;
    }
    else
    { 
        /* In case debug lib is not defined, the following macro won't cause panic so a return would be
         required for the function */
        MCP_ERROR("Invalid profile_handle\n");
        return NULL;
    }
}
#endif /* EXCLUDE_GATT_OTS_CLIENT_MODULE */
